#include <iostream>
#include <sstream>
#include <string>
#include <cstring>
#include <memory>
#include "speck.hpp"
#include "speckwrapper.hpp"
#include "bcstatistics.hpp"

namespace {

template<int N, int M>
std::unique_ptr<speck_blockcipher<N,M> > make_speck(int R)
{
	std::unique_ptr<speck_blockcipher<N,M> > up(new speck_blockcipher<N,M>());
	if (R>=0)
		up->rounds(R);
	return up;
}

} // anonymous namespace

int main(int argc, char *argv[])
{
	if (argc<2 || argc>3) {
		std::cout << "syntax:\n"
			"speckstatistics <speck-instance> [<rounds>]\n"
			"example: speckstatistics 64/128 12\n";
		return 0;
	}
	int R = -1;
	if (argc==3) {
		std::istringstream is (argv[2]);
		is >> R;
	}
	std::unique_ptr<blockcipher> bc;
	char const* const inst = argv[1];
	if      (std::strcmp(inst, "32/64" )==0) bc = make_speck<16,4>(R);
	else if (std::strcmp(inst, "48/72" )==0) bc = make_speck<24,3>(R);
	else if (std::strcmp(inst, "48/96" )==0) bc = make_speck<24,4>(R);
	else if (std::strcmp(inst, "64/96" )==0) bc = make_speck<32,3>(R);
	else if (std::strcmp(inst, "64/128")==0) bc = make_speck<32,4>(R);
	else if (std::strcmp(inst, "96/96" )==0) bc = make_speck<48,2>(R);
	else if (std::strcmp(inst, "96/144")==0) bc = make_speck<48,3>(R);
	else if (std::strcmp(inst,"128/128")==0) bc = make_speck<64,2>(R);
	else if (std::strcmp(inst,"128/192")==0) bc = make_speck<64,3>(R);
	else if (std::strcmp(inst,"128/256")==0) bc = make_speck<64,4>(R);
	if (!bc) {
		std::cout << "invalid instance, try 32/64, 48/72, 48/96, 64/96, 64/128,\n"
			"96/96, 96/144, 128/128, 128/192 or 128/256\n";
		return 1;
	}
	run_bc_test(*bc);
	return 0;
}
